package com.atguigu.exam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.service.KimiAiService;
import com.atguigu.exam.vo.AiGenerateRequestVo;
import com.atguigu.exam.vo.GradingResult;
import com.atguigu.exam.vo.QuestionImportVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.IterableGet;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.security.PublicKey;
import java.time.Duration;
import java.util.*;

/**
 * Kimi AI服务实现类
 * 调用Kimi API智能生成题目
 */
@Slf4j
@Service
public class KimiAiServiceImpl implements KimiAiService {

    @Value("${kimi.api.key}")
    private String kimiApiKey;

    @Value("${kimi.api.base-url}")
    private String kimiBaseUrl;

    @Value("${kimi.api.model}")
    private String kimiModel;

    // 注入 Kimi API 的 max-tokens 配置
    @Value("${kimi.api.max-tokens}")
    private Integer maxTokens;

    // 注入 Kimi API 的 temperature 配置
    @Value("${kimi.api.temperature}")
    private Double temperature;

    @Autowired
    private WebClient webClient;



    /**
     * 构建发送给ai的提示词
     */
    @Override
    public String buildPrompt(AiGenerateRequestVo request) {
       StringBuilder prompt = new StringBuilder();
       prompt.append("请为我生成").append(request.getCount()).append("道关于【").append(request.getTopic()).append("】的题目。\n\n");
       prompt.append("要求：\n");

        /**
         * 题目类型要求
         */
        if (request.getTypes() != null && !request.getTypes().isEmpty()){
            List<String> typeList = Arrays.asList(request.getTypes().split(","));
            prompt.append("- 题目类型：");
            for (String type : typeList) {
                switch (type.trim()){
                    case "CHOICE":
                        prompt.append("选择题");
                        if (request.getIncludeMultiple()!=null && request.getIncludeMultiple()){
                            prompt.append("(包含单选和多选题)");
                        }
                        prompt.append(" ");
                        break;
                    case "JUDGE":
                        prompt.append("判断题（**重要：确保正确答案和错误答案的数量大致平衡，不要全部都是正确或错误**）");
                        break;
                    case "TEXT":
                        prompt.append("简答题");
                        break;
                }
            }
            prompt.append("\n");
        }

//        难度要求
        if (request.getDifficulty() != null){
            String difficultText = switch (request.getDifficulty()){
                case "EASY" -> "简单";
                case "MEDIUM" -> "中等";
                case "HARD" -> "困难";
                default -> "中等";
            };
            prompt.append("- 难度等级：").append(difficultText).append("\n");
        }

//        额外要求
        if (request.getRequirements() != null && !request.getRequirements().isEmpty()){
            prompt.append("- 特殊要求：").append(request.getRequirements()).append("\n");
        }

//        判断题特别要求
        if (request.getTypes() != null && request.getTypes().contains("JUDGE")){
            prompt.append("- **判断题特别要求**：\n");
            prompt.append("  * 确保生成的判断题中，正确答案(TRUE)和错误答案(FALSE)的数量尽量平衡\n");
            prompt.append("  * 不要所有判断题都是正确的或都是错误的\n");
            prompt.append("  * 错误的陈述应该是常见的误解或容易混淆的概念\n");
            prompt.append("  * 正确的陈述应该是重要的基础知识点\n");
        }
        prompt.append("\n请严格按照以下JSON格式返回，不要包含任何其他文字：\n");
        prompt.append("```json\n");
        prompt.append("{\n");
        prompt.append("  \"questions\": [\n");
        prompt.append("    {\n");
        prompt.append("      \"title\": \"题目内容\",\n");
        prompt.append("      \"type\": \"CHOICE|JUDGE|TEXT\",\n");
        prompt.append("      \"multi\": true/false,\n");
        prompt.append("      \"difficulty\": \"EASY|MEDIUM|HARD\",\n");
        prompt.append("      \"score\": 5,\n");
        prompt.append("      \"choices\": [\n");
        prompt.append("        {\"content\": \"选项内容\", \"isCorrect\": true/false, \"sort\": 1}\n");
        prompt.append("      ],\n");
        prompt.append("      \"answer\": \"TRUE或FALSE(判断题专用)|文本答案(简答题专用)\",\n");
        prompt.append("      \"analysis\": \"题目解析\"\n");
        prompt.append("    }\n");
        prompt.append("  ]\n");
        prompt.append("}\n");
        prompt.append("```\n\n");

        prompt.append("注意：\n");
        prompt.append("1. 选择题必须有choices数组，判断题和简答题设置answer字段\n");
        prompt.append("2. 多选题的multi字段设为true，单选题设为false\n");
        prompt.append("3. **判断题的answer字段只能是\"TRUE\"或\"FALSE\"，请确保答案分布合理**\n");
        prompt.append("4. 每道题都要有详细的解析\n");
        prompt.append("5. 题目要有实际价值，贴近实际应用场景\n");
        prompt.append("6. 严格按照JSON格式返回，确保可以正确解析\n");

//        如果只生成判断题，强调答案要平衡
        if (request.getTypes() != null && request.getTypes().equals("JUDGE") && request.getCount() > 1){
            prompt.append("7. **判断题答案分布要求**：在").append(request.getCount()).append("道判断题中，");
            int halfCount = request.getCount() / 2;
            if (request.getCount() % 2 == 0){
                prompt.append("请生成").append(halfCount).append("道正确(TRUE)和").append(halfCount).append("道错误(FALSE)的题目");
            }else {
                prompt.append("请生成约").append(halfCount).append("-").append(halfCount + 1).append("道正确(TRUE)和约").append(halfCount).append("-").append(halfCount + 1).append("道错误(FALSE)的题目");
            }
        }
        return prompt.toString();
    }


    /**
     * kimi智能题目生成业务方法：检查kimi核心参数、生成提示词、调用kimi模型、结果解析处理
     * @param request
     * @return
     */
    @Override
    public List<QuestionImportVo> generateQuestions(AiGenerateRequestVo request) {
//        1.添加核心参数调试日志
        log.info("kimi API生成AI题目开始！");
        log.info("kimi API配置检查:");
        log.info("kimiApiKey:{}",kimiApiKey);
        log.info("kimiBaseUrl: {}", kimiBaseUrl);
        log.info("kimiModel: {}", kimiModel);

//        2.创建提示词
        String prompt = buildPrompt(request);
        log.info("本次拼接的提示词为：{}",prompt);

//        3.调用kimi api
        String response = callKimiApi(prompt);
        log.error(response);

//        4.结果集解析：截取json数据部分、查找json代码块
        int startIndex = response.indexOf("```json");
        int endIndex = response.lastIndexOf("```");
        if (startIndex != -1 && endIndex != 1 && endIndex > startIndex){
//            接收结果: "```json" 这个字符串的长度是 7, startIndex + 7 的目的是跳过
//      "```json" 这部分前缀内容**，从 "```json" 结束的位置开始截取，一直到最后一个 "```"
//      出现的位置（endIndex），这样就能得到中间纯 JSON 格式的数据内容了。
            response = response.substring(startIndex + 7, endIndex).trim();
        }else {
            throw new RuntimeException("ai生成题目格式异常，无法解析！");
        }

//        把Response中的Json串截取不同的部分信息：
        List<QuestionImportVo> questions = new ArrayList<>();
        JSONObject jsonResponse = JSON.parseObject(response);
//        截取数组问题部分：
        JSONArray quesitonsArray = jsonResponse.getJSONArray("questions");
        for (int i = 0; i < quesitonsArray.size(); i++) {
            JSONObject questionJson = quesitonsArray.getJSONObject(i);
            QuestionImportVo question = new QuestionImportVo();
            question.setTitle(questionJson.getString("title"));
            question.setType(questionJson.getString("type"));
            question.setMulti(questionJson.getBoolean("multi"));
            question.setDifficulty(questionJson.getString("difficulty"));
            question.setScore(questionJson.getInteger("score"));
            question.setAnalysis(questionJson.getString("analysis"));
            question.setCategoryId(request.getCategoryId());

//            处理选择题选项
            if ("CHOICE".equals(question.getType()) && questionJson.containsKey("choices")){
                JSONArray choicesArray = questionJson.getJSONArray("choices");
                List<QuestionImportVo.ChoiceImportDto> choices = new ArrayList<>();
                for (int j = 0; j < choicesArray.size(); j++) {
                    JSONObject choiceJson = choicesArray.getJSONObject(j);
                    QuestionImportVo.ChoiceImportDto choice = new QuestionImportVo.ChoiceImportDto();
                    choice.setContent(choiceJson.getString("content"));
                    choice.setIsCorrect(choiceJson.getBoolean("isCorrect"));
                    choice.setSort(choiceJson.getInteger("sort"));
                    choices.add(choice);
              }
                question.setChoices(choices);
            }else {
//                判断题和简答题
                String rawAnswer = questionJson.getString("answer");
//                对判断题答案进行标准化处理：
                if ("JUDGE".equals(question.getType()) && rawAnswer != null){
//                    将中文答案转换为英文标准答案
                    if ("正确".equals(rawAnswer) || "对".equals(rawAnswer) || "TURE".equalsIgnoreCase(rawAnswer)){
                        rawAnswer = "TRUE";
                    }else if ("错误".equals(rawAnswer) || "错".equals(rawAnswer) || "FALSE".equalsIgnoreCase(rawAnswer)){
                        rawAnswer = "FALSE";
                    }
//                    如果都不匹配，记录日志但不抛异常，让验证逻辑处理：
                    if (!"TRUE".equals(rawAnswer) && !"FALSE".equals(rawAnswer)){
                        log.warn("AI生成的判断题答案格式不标准: {}, 题目: {}", rawAnswer, question.getTitle());
                    }
                }
                question.setAnswer(rawAnswer);
            }
            questions.add(question);
        }
        return questions;
    }

    /**
     * 构建判卷提示词
     */
    public String buildGradingPrompt(Question question, String userAnswer, Integer maxScore) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一名专业的考试阅卷老师，请对以下题目进行判卷：\n\n");

        prompt.append("【题目信息】\n");
        prompt.append("题型：").append(getQuestionTypeText(question.getType())).append("\n");
        prompt.append("题目：").append(question.getTitle()).append("\n");
        prompt.append("标准答案：").append(question.getAnswer().getAnswer()).append("\n");
        prompt.append("满分：").append(maxScore).append("分\n\n");

        prompt.append("【学生答案】\n");
        prompt.append(userAnswer.trim().isEmpty() ? "（未作答）" : userAnswer).append("\n\n");

        prompt.append("【判卷要求】\n");
        if ("CHOICE".equals(question.getType()) || "JUDGE".equals(question.getType())) {
            prompt.append("- 客观题：答案完全正确得满分，答案错误得0分\n");
        } else if ("TEXT".equals(question.getType())) {
            prompt.append("- 主观题：根据答案的准确性、完整性、逻辑性进行评分\n");
            prompt.append("- 答案要点正确且完整：80-100%分数\n");
            prompt.append("- 答案基本正确但不够完整：60-80%分数\n");
            prompt.append("- 答案部分正确：30-60%分数\n");
            prompt.append("- 答案完全错误或未作答：0分\n");
        }

        prompt.append("\n请按以下JSON格式返回判卷结果：\n");
        prompt.append("{\n");
        prompt.append("  \"score\": 实际得分(整数),\n");
        prompt.append("  \"feedback\": \"具体的评价反馈(50字以内)\",\n");
        prompt.append("  \"reason\": \"扣分原因或得分依据(30字以内)\"\n");
        prompt.append("}");

        return prompt.toString();
    }

    @Override
    public String buildSummaryPrompt(Integer totalScore, Integer maxScore, Integer questionCount, Integer correctCount) {
        double percentage =(double)(totalScore / maxScore * 100);
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一名资深的教育专家，请为学生的考试表现提供专业的总评和学习建议：\n\n");
        prompt.append("【考试成绩】\n");
        prompt.append("总得分").append(totalScore).append("/").append(maxScore).append("分\n");
        prompt.append("得分率：").append(String.format("%.1f",percentage)).append("%\n");
        prompt.append("题目总数：").append(questionCount).append("道\n");
        prompt.append("答对题数：").append(correctCount).append("道\n\n");
        prompt.append("【要求】\n");
        prompt.append("请提供一份150字左右的考试总评，包括：\n");
        prompt.append("1. 对本次考试表现的客观评价\n");
        prompt.append("2. 指出优势和不足之处\n");
        prompt.append("3. 提供具体的学习建议和改进方向\n");
        prompt.append("4. 给予鼓励和激励\n\n");
        prompt.append("请直接返回总评内容，无需特殊格式：");
        return prompt.toString();
    }

    @Override
    public GradingResult gradeQuestion(Question question, String userAnswer, Integer maxScore) {
        try {
            String prompt = buildGradingPrompt(question,userAnswer,maxScore);
            String response = callKimiApi(prompt);
            return parseGradingResponse(response,maxScore);
        }catch (Exception e){
            log.error("ai判卷失败。题目ID:{},错误:{}",question.getId(),e.getMessage());
//            返回默认评分结果：
            return new GradingResult(0,"AI判卷服务暂时不可用，请手动批阅。","系统错误");
        }
    }

    /**
     * 解析判卷响应
     * @param response
     * @param maxScore
     * @return
     */
    private GradingResult parseGradingResponse(String response, Integer maxScore) {
            try {
//                尝试解析JSON格式的响应
                JSONObject json = JSON.parseObject(response);
                Integer score = json.getInteger("score");
                String feedback = json.getString("feedback");
                String reason = json.getString("reason");

                //分数范围检查
                if (score == null || score < 0 )score = 0;
                if (score > maxScore) score = maxScore;
                return new GradingResult(score,feedback,reason);
            }catch (Exception e){
                log.warn("解析AI响应失败，使用默认解析: {}", e.getMessage());
//                如果JSON解析失败，尝试从文本中提取信息：
                return parseTextResponse(response,maxScore);
            }



    }

    /**
     * 从响应文本中解析结果
     * @param response
     * @param maxScore
     * @return
     */
    private GradingResult parseTextResponse(String response, Integer maxScore) {
//        简单的文本解析逻辑：
        Integer score = 0;
        String feedback = "AI自动判卷完成";
        String reason = "系统自动评分";

//        尝试从响应中提取分数：
        String[] lines = response.split("\n");
        for (String line : lines) {
//            . 匹配任意单个字符（除了换行符）
//            * 表示前面的元素可以出现 0 次或多次
//            \\d+ 匹配一个或多个数字（\\d 表示数字字符，+ 表示至少出现一次）
//            整体来看，这个正则表达式的作用是检查字符串中是否包含至少一个数字。
            if (line.contains("分") && line.matches(".*\\d+.*")){
                try {
                    String numberStr = line.replaceAll("[^0-9]","");
//                    replaceAll("[^0-9]", "") 是一个字符串替换操作
//                    正则表达式 [^0-9] 表示 "所有不是数字的字符"（^ 在方括号内表示 "非" 的意思）
//                    第二个参数 "" 表示用空字符串替换，也就是删除匹配到的非数字字符
                    if (!numberStr.isEmpty()){
                        Integer extractedScore = Integer.parseInt(numberStr);
                        if (extractedScore <= maxScore){
                            score = extractedScore;
                        }
                    }
                }catch (NumberFormatException ignored){

                }
            }
        }

//        截取响应的前100个字符作为反馈
        if (response.length() > 100){
            feedback = response.substring(0,100)+"...";
        }else {
            feedback = response;
        }
        return new GradingResult(score, feedback, reason);
    }


    /**
     * 获取题目类型文本
     * @param type
     * @return
     */
    private String getQuestionTypeText(String type) {
        Map<String, String> typeMap = new HashMap<>();
        typeMap.put("CHOICE","选择题");
        typeMap.put("JUDGE","判断题");
        typeMap.put("TEXT","简答题");
        return typeMap.getOrDefault(type,"未知题型");
    }


    /**
     * 封装kimi的调用过程
     * @param prompt
     * @return
     */
    private String callKimiApi(String prompt) {
        if (kimiApiKey == null || kimiApiKey.isEmpty()){
            throw new RuntimeException("未配置Kimi API密钥，请在配置文件中设置kimi.api.api-key");
        }
        log.info("开始调用Kimi API生成题目……");
//        1.开始拼接请求体成一整个json格式：
        JSONObject requestBody = new JSONObject();
        requestBody.put("model",kimiModel);
        requestBody.put("max_tokens",maxTokens);
        requestBody.put("temperature",temperature);

//        messages数组：
        JSONArray messages = new JSONArray();
        JSONObject userMessage = new JSONObject();
        userMessage.put("role","user");
        userMessage.put("content",prompt);
        messages.add(userMessage);
        requestBody.put("messages",messages);

//        调用kimi，建议添加重试机制，因为网络波动导致的失败概率很高
        int maxRetries = 3;
        for (int attempt = 1;attempt <= maxRetries;attempt++){
            try {
                log.info("第{}次尝试调用kimi API",attempt);
//                发送请求，增加超时时间到120秒
                Mono<String> responseMono = webClient.post().uri(kimiBaseUrl+"/chat/completions")
                        .header(HttpHeaders.AUTHORIZATION,"Bearer "+kimiApiKey)
                        .bodyValue(requestBody.toString())
                        .retrieve()
                        .bodyToMono(String.class)
                        .timeout(Duration.ofSeconds(120));
//                增加到120秒超时
                String response = responseMono.block();
                log.info("kimi API调用成功，响应长度:{}",response != null ? response.length() : 0);
//                解析响应，获取响应正文
                JSONObject responseJson = JSON.parseObject(response);
//                如果包含error key，依然需要尝试
                if (responseJson.containsKey("error")){
                    String errorMessage = responseJson.getJSONObject("error").getString("message");
                    log.error("kimi API返回错误:{}",errorMessage);
                    if (attempt < maxRetries){
                        log.info("遇到限流，等待{}秒后重试...",attempt * 3);
                       Thread.sleep(attempt * 3000); //等待次数逐渐翻倍
                        continue; //跳过当前循环体中剩余的代码，直接进入下一次循环:（attempt+1）
                    }
                }
//                没有错误error，正确结果获取：
                JSONArray choices = responseJson.getJSONArray("choices");
                if (choices != null && !choices.isEmpty()){
                    String content = choices.getJSONObject(0).getJSONObject("message").getString("content");
                    log.info("AI生成内容获取成功，内容长度：{}",content.length());
                    return content;
                }else {
                    throw new RuntimeException("kimi API 返回的响应格式不正确！");
                }
            } catch (Exception e) {
                log.error("第{}次调用kimi API失败:{}",attempt,e.getMessage());
//                尝试次数等于最大次数时抛出异常
                if (attempt == maxRetries){
                    throw new RuntimeException("AI服务响应超时，请稍后重试。如果问题持续存在，建议减少生成题目数量或简化需求描述！");
                }
//                如果没有达到最大次数，休眠再尝试！
//                如果不是最后一次尝试，就等待后重试！
                try {
                    Thread.sleep(2000);
                }catch (InterruptedException ie){
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("AI生成被中断");
                }
            }
        }
        throw new RuntimeException("AI生成题目失败，已重试"+maxRetries+"次");
    }

    /**
     * 生成考试总评和建议
     */
    public String generateExamSummary(Integer totalScore, Integer maxScore, Integer questionCount, Integer correctCount){
        try {
            String prompt = buildSummaryPrompt(totalScore,maxScore,questionCount,correctCount);
            return callKimiApi(prompt);
        }catch (Exception e){
            log.error("生成考试总评失败:{}",e.getMessage());
//            返回默认总评：
            double percentage = (double) totalScore / maxScore * 100;
            return String.format("本次考试总分 %d/%d 分（%.1f%%）。建议多加练习，持续提升！",totalScore,maxScore,percentage);
        }
    }





}